package me.edzh.spring.bootstrap.resolvers;

import lombok.extern.log4j.Log4j;
import me.edzh.spring.bootstrap.annotations.EncryptedRequestBody;
import me.edzh.spring.bootstrap.annotations.SignedRequestBody;
import me.edzh.spring.bootstrap.processor.SignAndEncryptProcessor;
import me.edzh.spring.bootstrap.utils.ResultCode;
import me.edzh.spring.bootstrap.utils.exception.ServiceException;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;

@Log4j
public class SignedBodyResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private SignAndEncryptProcessor signAndEncryptProcessor;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(SignedRequestBody.class) || parameter.hasParameterAnnotation(EncryptedRequestBody.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        ServletServerHttpRequest request = new ServletServerHttpRequest(webRequest.getNativeRequest(HttpServletRequest.class));
        if (!request.getHeaders().containsKey("SIGN") || request.getHeaders().size() == 0) {
            throw new ServiceException(ResultCode.ERROR_SIGN_CHECK_ERR, "there is no SIGN header in request");
        }
        String sign = request.getHeaders().get("SIGN").get(0);
        log.info("sign:" + sign);
        byte[] body = IOUtils.toByteArray(request.getBody());
        return signAndEncryptProcessor.checkSignAndConvertBody(sign, body, parameter.hasParameterAnnotation(EncryptedRequestBody.class), parameter.getParameterType());
    }


}
